use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::helper::{
    build_regex, extract_combined_index, extract_data, extract_from_multi_patterns,
};

/// cpu 相关信息
/// ```text
/// https://www.cisco.com/c/en/us/support/docs/ip/simple-network-management-protocol-snmp/15215-collect-cpu-util-snmp.html
/// ```
/// -  cpmCPUTotal5secRev(.1.3.6.1.4.1.9.9.109.1.1.1.1.6): The overall CPU busy percentage in the last five-second period. This object deprecates the object cpmCPUTotal5sec and increases the value range to (0..100).
///
/// -  cpmCPUTotal1minRev(.1.3.6.1.4.1.9.9.109.1.1.1.1.7): The overall CPU busy percentage in the last one-minute period. This object deprecates the object cpmCPUTotal1min and increases the value range to (0..100).
///
/// -  cpmCPUTotal5minRev(.1.3.6.1.4.1.9.9.109.1.1.1.1.8): The overall CPU busy percentage in the last five-minute period. This object deprecates the object cpmCPUTotal5min and increases the value range to (0..100).

#[derive(Debug, Serialize, Deserialize, Default, JsonSchema, Clone)]
pub struct CpuData {
    /// CPU 5 秒使用率
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.3
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.3.19 = Gauge32: 5
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.6.19 = Gauge32: 4
    pub cpu_use_5_seconds: String,
    /// CPU 1分钟使用
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.4
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.4.19 = Gauge32: 4
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.7.19 = Gauge32: 4
    pub cpu_use_1_minutes: String,
    /// CPU 5分钟使用
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.5
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.5.19 = Gauge32: 5
    ///
    /// .3.6.1.4.1.9.9.109.1.1.1.1.8.19 = Gauge32: 5
    pub cpu_use_5_minutes: String,
    pub cpu_details: Vec<CpuDetail>,
    /// cpu 数量
    ///
    /// hillstone 1.3.6.1.4.1.28557.2.2.1.3
    ///
    /// iso.3.6.1.4.1.28557.2.2.1.3.0 = INTEGER: 1
    pub cpu_num: String,
}

#[derive(Debug, Serialize, Deserialize, Default, JsonSchema, Clone)]
pub struct CpuDetail {
    /// cpu 内存 标志号，华为防火墙自动分配用来标识CPU与内存
    pub index: String,

    /// CPU 使用率
    ///
    /// iso.3.6.1.4.1.2011.5.25.31.1.1.1.1.5
    ///
    /// iso.3.6.1.4.1.2011.5.25.31.1.1.1.1.5.335544321 = INTEGER: 0
    ///
    /// iso.3.6.1.4.1.2011.5.25.31.1.1.1.1.5.603979777 = INTEGER: 20
    pub cpu_usage_percent: String,

    /// CPU使用阈值
    ///
    /// iso.3.6.1.4.1.2011.5.25.31.1.1.1.1.6
    ///
    /// iso.3.6.1.4.1.2011.5.25.31.1.1.1.1.6.335544321 = INTEGER: 0
    ///
    /// iso.3.6.1.4.1.2011.5.25.31.1.1.1.1.6.603979777 = INTEGER: 80
    pub cpu_usage_threshold: String,
}

impl CpuDetail {
    fn values(text: &str) -> Vec<Self> {
        let re = build_regex(r"3.6.1.4.1.2011.5.25.31.1.1.1.1.5.(\d+)");
        let mut results = vec![];
        for cap in re.captures_iter(text) {
            let index = &cap[1];
            results.push(Self {
                index: index.to_owned(),
                cpu_usage_percent: extract_combined_index(
                    "3.6.1.4.1.2011.5.25.31.1.1.1.1.5.",
                    index,
                    r" = INTEGER: (\d+)",
                    text,
                ),
                cpu_usage_threshold: extract_combined_index(
                    ".3.6.1.4.1.2011.5.25.31.1.1.1.1.6.",
                    index,
                    r" = INTEGER: (\d+)",
                    text,
                ),
            })
        }
        results
    }
}

impl CpuData {
    pub fn new(value: &str) -> Self {
        let prefix = ".3.6.1.4.1.9.9.109.1.1.1.1";
        Self {
            cpu_num: extract_data(r".3.6.1.4.1.28557.2.2.1.3.0 = INTEGER: (\d+)", value),
            cpu_use_5_seconds: extract_from_multi_patterns(
                &[
                    (&format!(r"{prefix}.3.(\d+) = Gauge32: (\d+)"), 2),
                    (&format!(r"{prefix}.6.(\d+) = Gauge32: (\d+)"), 2),
                ],
                value,
            ),
            cpu_use_1_minutes: extract_from_multi_patterns(
                &[
                    (&format!(r"{prefix}.4.(\d+) = Gauge32: (\d+)"), 2),
                    (&format!(r"{prefix}.7.(\d+) = Gauge32: (\d+)"), 2),
                ],
                value,
            ),
            cpu_use_5_minutes: extract_from_multi_patterns(
                &[
                    (&format!(r"{prefix}.5.(\d+) = Gauge32: (\d+)"), 2),
                    (&format!(r"{prefix}.8.(\d+) = Gauge32: (\d+)"), 2),
                ],
                value,
            ),
            cpu_details: CpuDetail::values(value),
        }
    }
}
